package p2p.client.message;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.UUID;

import p2p.command.Command;
import p2p.peer.Peer;
import p2p.util.Utils;

/**
 * 
 * @author p2pGroup
 * 
 * Message Class represents one Message in the p2p - Protokoll. In the following the 
 * architektur of one message is given 
 * 
 * -----------------------------------------------------------------------------------------------
 * |0 - 15 = UUID | 16 = Command | 17 = ack | 18 - 19 = sqn | 20 - 21 = tn | paylood  | = max 1024 bytes
 * ------------------------------------------------------------------------------------------------
 */
public class Message {

	private int command;
	private boolean ack;
	private UUID uuid;
	private int sequenceNumber;
	private int totalNumber;
	private byte[] totalPayload;
	private byte[] dataPayload;
	private Command commandObject;
	private String ip;
	private int port;
	
	public Message(int command) {
		
		this.command = command;
		uuid = UUID.randomUUID();
	
	}
	
	//public Message(int command, Client client) {
	public Message(int command, String ip, int port) {
		
		this.totalPayload = new byte[1024];
		this.command = command;
		uuid = UUID.randomUUID();
		this.ip = ip;
		this.port = port;
		
		this.totalPayload = Arrays.copyOf(Utils.uuidToByteArray(uuid), 1024);
		this.totalPayload[16] = (byte) this.command;
		this.totalPayload[17] = 0;
		this.totalPayload = Utils.insertArray(totalPayload, Utils.intToByteArray(1), 18);
		this.totalPayload = Utils.insertArray(totalPayload, Utils.intToByteArray(1), 20);
		//TODO refactor ip of the client
		//this.totalPayload = Utils.insertArray(totalPayload, client.getBytes(), 22);
		
		//Inserting IP address into totalPayload
		byte[] ipByteArray = Utils.getBytesFromIp(this.getIp());					
		this.totalPayload[22] = ipByteArray[0];
		this.totalPayload[23] = ipByteArray[1];
		this.totalPayload[24] = ipByteArray[2];
		this.totalPayload[25] = ipByteArray[3];

		//Inserting Port into totalPayload
		byte[] portByteArray = Utils.intToByteArray(Peer.getInstance().getPeerPort());		
		this.totalPayload[26] = portByteArray[0];
		this.totalPayload[27] = portByteArray[1];
		this.totalPayload[28] = portByteArray[2];
		this.totalPayload[29] = portByteArray[3];
		
//		System.out.println("port : " + port);
//		System.out.println("ip : " + ip);
//		
//		byte [] ipInfo1 = new byte [4];
//		ipInfo1[0] = this.totalPayload[22];
//		ipInfo1[1] = this.totalPayload[23];
//		ipInfo1[2] = this.totalPayload[24];
//		ipInfo1[3] = this.totalPayload[25];		
//		String testIP = Utils.getIpFromBytesArray(ipInfo1);
//		
//		byte [] portInfo1 = new byte[4];
//		portInfo1[0] = this.totalPayload[26];
//		portInfo1[1] = this.totalPayload[27];
//		portInfo1[2] = this.totalPayload[28];
//		portInfo1[3] = this.totalPayload[29];
//		int testPort = Utils.byteArrayToInt(portInfo1);
//			
//		System.out.println("Test PORT " + testPort);		
//		System.out.println("Test ip " + testIP);	
//		
//		System.out.println("[22] : " + this.totalPayload[22]);
//		System.out.println("[23] : " + this.totalPayload[23]);
//		System.out.println("[24] : " + this.totalPayload[24]);
//		System.out.println("[25] : " + this.totalPayload[25]);
//		System.out.println("[26] : " + this.totalPayload[26]);
//		System.out.println("[27] : " + this.totalPayload[27]);
//		System.out.println("[28] : " + this.totalPayload[28]);
//		System.out.println("[29] : " + this.totalPayload[29]);
//		System.out.println("[26] : " + this.totalPayload[30]);
//		System.out.println("[27] : " + this.totalPayload[31]);
//		System.out.println("[28] : " + this.totalPayload[32]);
//		System.out.println("[29] : " + this.totalPayload[33]);
//		System.out.println("[26] : " + this.totalPayload[34]);
//		System.out.println("[27] : " + this.totalPayload[35]);
//		System.out.println("[28] : " + this.totalPayload[36]);
//		System.out.println("[29] : " + this.totalPayload[37]);
	}

	public Message(byte[] recieveData) {
		
		this.totalPayload = recieveData;
		this.uuid = Utils.toUUID(Arrays.copyOfRange(recieveData, 0, 16));
		this.command = recieveData[16];
		this.ack = recieveData[17] > 0 ? true : false;
		//this.sequenceNumber = Utils.byteArrayToInt(Utils.getSubArray(recieveData, 18, 20));
		//this.totalNumber = Utils.byteArrayToInt(Utils.getSubArray(recieveData, 20, 22));
		//this.dataPayload = Arrays.copyOfRange(recieveData, 22, 1023);
	
	}
	
	//TODO Remove that method , because it is not used
	public byte[] getMessageBytes() {

		byte[] uuidArray = Utils.uuidToByteArray(uuid);
		
		byte[] requestData = Arrays.copyOf(uuidArray, 1024);
		
		requestData[16] = (byte) this.command;
		
		return requestData;
		
	}
	
	public String toString() {
		return "UUID: " + uuid.toString() + " Command " + this.command;
	}

	public int getCommand() {
		return command;
	}

	public boolean isAck() {
		return ack;
	}

	public UUID getUuid() {
		return uuid;
	}
	
	public int getSequenceNumber() {
		return sequenceNumber;
	}

	public int getTotalNumber() {
		return totalNumber;
	}

	public byte[] getTotalPayload() {
		return totalPayload;
	}

	public byte[] getDataPayload() {
		return dataPayload;
	}

	@Override
	public int hashCode() {
		return this.uuid.hashCode();
	}
	
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof Message){
			Message m = (Message) obj;
			if (m.getUuid().equals(this.uuid))
				return true;
			else
				return false;
		}
		return false;
	}

	public Command getCommandObject() {
		return commandObject;
	}

	public void setCommandObject(Command commandObject) {
		this.commandObject = commandObject;
	}
	
	public String getIp() {
		return ip;
	}

	public int getPort() {
		return port;
	}
	
}
